/*
 * Controlador.cpp
 *
 *  Created on: 24/11/2011
 *      Author: Arthur Holanda
 */

#include <FBase.h>
#include "controller/Controlador.h"
#include "db/DatabaseManager.h"
#include "db/InfoDB.h"
#include "model/Analisador.h"

using namespace Osp::Base::Collection;
using namespace Osp::Base::Utility;
using namespace Osp::Base;

Controlador* Controlador::controlador = 0;

Controlador::Controlador() {
	nomesViaveis = null;
	donoMaiorAposta = -1;
	jogadores[0] = null;
}

Controlador::~Controlador() {
	delete baralho;
	delete mesa;
}

void Controlador::Construct() {
	mesa = new Mao();
	baralho = new Baralho();
	maiorApostaRodada = 0;
	quantidadeJogadores = 1;
	dealer = 0;
	blind = 2;
	db = new DatabaseManager();
	db->Construct();
	ArrayList* perfis = db->GetPerfisOrderByNome();

	if (nomesViaveis != null){
		nomesViaveis->RemoveAll(true);
		delete nomesViaveis;
	}

	nomesViaveis = new ArrayList();
	nomesViaveis->Construct();

	for (int i=0; i < perfis->GetCount(); i++) {
		nomesViaveis->Add(*new String(((InfoDB*)perfis->GetAt(i))->GetNome().GetPointer()));
	}

	nomesViaveis->Add(*new String("Bob"));
	nomesViaveis->Add(*new String("John"));
	nomesViaveis->Add(*new String("James"));

	if (GetJogador() != null) {
		nomesViaveis->Remove(GetJogador()->GetNome(),true);
	}
}

void Controlador::SetJogador(Jogador *jogador) {
	jogadores[0] = jogador;
	jogador->SetControlador(this);
}

Baralho *Controlador::GetBaralho() {
	return this->baralho;
}

Mao* Controlador::GetMesa() {
	return mesa;
}

Jogador *Controlador::GetJogador() {
	return this->jogadores[0];
}

Controlador* Controlador::GetInstance() {
	if (!controlador) {
		controlador = new Controlador();
	}
	return controlador;
}

int Controlador::GetMaiorApostaRodada() {
	return maiorApostaRodada;
}

void Controlador::SetMaiorApostaRodada(int aposta) {
	this->maiorApostaRodada = aposta;
}

void Controlador::AddJogadores(int qtd) {
	String nome;
	for (int i=0; i < qtd; i++) {
		Jogador* j = new Jogador();
		nome = RecuperaNome();
		j->Construct(nome, 100);
		AdicionarJogador(j);
	}
}

String Controlador::RecuperaNome() {
	int i;
	String nome;

	i = Math::Rand() % nomesViaveis->GetCount();
	nome = *((String*)nomesViaveis->GetAt(i));

	nomesViaveis->Remove(nome);
	return nome;
}

int Controlador::GetPosicaoJogadorDaVez()
{
	return jogadorDaVez;
}

int Controlador::GetPosicaoDealer()
{
	return dealer;
}

bool Controlador::ExisteJogador(String nome) {
	Jogador* j;
	for (int i=0; i < quantidadeJogadores; i++) {
		j = jogadores[i];
		if (j->GetNome().Equals(nome, false)) {
			return true;
		}
	}
	return false;
}

void Controlador::AdicionarJogador(Jogador *jogador) {
	jogadores[quantidadeJogadores] = jogador;
	jogador->SetControlador(this);
	quantidadeJogadores++;
}

void Controlador::ProximoJogador() {
	jogadorDaVez = (jogadorDaVez+1) % quantidadeJogadores;

	if(jogadorDaVez == donoMaiorAposta){
		//FimRodadaAposta();
		return;
	}

	if(jogadorDaVez == dealer){
		if(!RodadaPodeTerminar()){
			//FimRodadaAposta();
			return;
		}
	}

	if(GetJogadorDaVez()->GetStatus() == DESISTIU){
		if(! RodadaPodeTerminar()){
			ProximoJogador();
		}else{
			//FimRodadaAposta();
		}
	}
}

void Controlador::JogadorJogou(Acao *acao) {
	switch (acao->acao) {
	case APOSTAR:
		if(acao->valor > maiorApostaRodada){
			maiorApostaRodada = acao->valor;
			donoMaiorAposta = jogadorDaVez;
		}
		break;
	case AUMENTAR:
		if(acao->valor > maiorApostaRodada){
			maiorApostaRodada = acao->valor;
			donoMaiorAposta = jogadorDaVez;
		}
		break;
	case COBRIR:
		break;
	case PASSAR:
		if(donoMaiorAposta == -1){
			donoMaiorAposta = jogadorDaVez;
		}
		break;
	case DESISTIR:
		this->apostaAcumulada += GetJogadorDaVez()->GetApostaRodada();
		break;
	default:
		break;
	}

	if(listener != null){
		listener->OnJogadorJogou(acao);
	}
}

/*pega as apostas dos jogadores que aida estao o jogo*/
void Controlador::FimRodadaAposta() {
	for (int i = 0; i < quantidadeJogadores; ++i) {
		if(jogadores[i]->GetStatus() == JOGANDO){
			apostaAcumulada += jogadores[i]->GetApostaRodada();
		}
	}

	if(listener != null){
		listener->OnFimRodadaAposta();
	}
}

Jogador *Controlador::GetJogador(int posicao) {
	return jogadores[posicao];
}

void Controlador::FimPartida() {
	if(listener != null){
		listener->OnFimPartida();
	}
}

void Controlador::InicioJogadaDaVez() {
	if(jogadorDaVez != 0){
		JogadorJogou(GetJogadorDaVez()->Jogar());
	}else{
		if(listener != null){
			listener->OnInicioJogadaJogador();
		}
	}
}

void Controlador::RemoverJogador(int posicao) {
	for (int i = posicao; i < quantidadeJogadores; ++i) {
		jogadores[i] = jogadores[i+1];
	}
	quantidadeJogadores--;
}

Jogador* Controlador::GetDealer() {
	return jogadores[dealer];
}

Jogador *Controlador::GetJogadorDaVez()
{
	return jogadores[jogadorDaVez];
}

bool Controlador::RodadaPodeTerminar() {
	if(jogadorDaVez == donoMaiorAposta){
		return true;
	}



	if(jogadorDaVez + 1 == dealer){
		for (int i = 0; i < quantidadeJogadores; ++i) {
			if(jogadores[i]->GetStatus() == JOGANDO &&
					jogadores[i]->GetApostaRodada() != GetMaiorApostaRodada())
			{
				return false;
			}
		}
	}else{
		return false;
	}

	return true;
}

void Controlador::ColocarCartaNaMesa()
{
	Carta* c;
	int numCartas;

	if(mesa->GetQtdCartas() == 0){
		numCartas = 3;
	}else{
		numCartas = 1;
	}

	for (int i = 0; i < numCartas; ++i) {
		c = baralho->DarCarta();
		mesa->PegarCarta(c);
	}
}

void Controlador::RecebeuBlinds() {
	if(listener != null){
		listener->OnRecebeuBlinds();
	}
}

void Controlador::PagaVencedor() {
	ArrayList* vencedores = new ArrayList();
	vencedores->Construct(quantidadeJogadores);
	Combinacao* melhorCombinacao = null;
	Combinacao* outra = null;
	int vencedor;

	Analisador* analisador = new Analisador();


	//checar se foi o caso de todos desistiram
	if(QuantidadeJogadoresJogando() == 1){
		for (int i = 0; i < quantidadeJogadores; ++i) {
			if(jogadores[i]->GetStatus() == JOGANDO){
				jogadores[i]->Receber(GetApostaAcumulada());
				break;
			}
		}
	}else{
		for (int i = 0; i < quantidadeJogadores; ++i) {
			if(jogadores[i]->GetStatus() != DESISTIU){
				melhorCombinacao = analisador->GetCombinacaoN(jogadores[i]->GetMao(), mesa);
				vencedor = i;
				break;
			}
		}

		for (int i = 0; i < quantidadeJogadores; ++i) {
			if(jogadores[i]->GetStatus() != DESISTIU){
				outra = analisador->GetCombinacaoN(jogadores[i]->GetMao(), mesa);
				if(outra->CompareTo(melhorCombinacao)){
					melhorCombinacao = outra;
					vencedor = i;
				}
			}
		}

		GetJogador(vencedor)->Receber(GetApostaAcumulada());

	}

	if(listener != null){
		listener->OnPagaVencedor(GetJogador(vencedor), melhorCombinacao);
	}

}

void Controlador::InicioRodadaDeAposta() {

	if(mesa->GetQtdCartas() == 0){
		for (int i = 0; i < quantidadeJogadores; ++i) {
			apostaAcumulada += jogadores[i]->GetApostaRodada();
		}
	}

	if(mesa->GetQtdCartas() == 5){
		AppLog("Vai pagar vencedor");
		PagaVencedor();
		return;
	}

	ColocarCartaNaMesa();
	donoMaiorAposta = -1;
	for(int i = 0;i < quantidadeJogadores;++i){
		if(jogadores[i]->GetStatus() == JOGANDO){
			jogadores[i]->IniciarRodada();
		}
	}

	jogadorDaVez = dealer;

	if(listener != null){
		listener->OnInicioRodadaDeAposta();
	}
}

void Controlador::SolicitarBlind() {
	for (int i = 1; i < quantidadeJogadores; ++i) {//NAO PEGA O BLIND DO JOGADOR
		if(jogadores[i]->GetDinheiro() >= blind){
			jogadores[i]->Apostar(blind);
		}
	}

	if(listener != null){
		listener->OnSolicitarBlind();
	}
}

int Controlador::GetApostaAcumulada(){
	return apostaAcumulada;
}

void Controlador::SetListener(IListenerControlador* listener){
	this->listener = listener;
}

void Controlador::DarCartasJogadores() {
	Jogador* j;

	for (int i = 0; i < quantidadeJogadores; ++i) {
		j = jogadores[i];
		j->PuxarCarta();
	}

	for (int i = 0; i < quantidadeJogadores; ++i) {
		j = jogadores[i];
		j->PuxarCarta();
	}

	if(listener != null){
		listener->OnDarCartasJogadores();
	}
}

int Controlador::QuantidadeJogadoresJogando(){
	int jogando;

	for (int i = 0; i < quantidadeJogadores; ++i) {
		if(jogadores[i]->GetStatus() == JOGANDO){
			jogando++;
		}
	}

	return jogando;
}

void Controlador::ProximoDealer()
{
	dealer = (dealer+1)%quantidadeJogadores;

	if(GetDealer()->GetDinheiro() < blind){
		RemoverJogador(dealer);
		ProximoDealer();
	}
}

void Controlador::InicioPartida() {

	apostaAcumulada = 0;

	donoMaiorAposta = -1;

	for (int i = 0; i < quantidadeJogadores; ++i) {
		jogadores[i]->IniciarPartida();
	}

	ProximoDealer();
	jogadorDaVez = dealer;

	if(listener != null){
		listener->OnInicioPartida();
	}

}

int Controlador::GetBlind(){
	return blind;
}

void Controlador::SetBlind(int blind){
	this->blind = blind;
}
